package handle

import (
	"fmt"
	"github.com/golang/protobuf/proto"
	. "leaf/cache"
	. "leaf/common"
	"leaf/core/cache"
	"leaf/core/cluster"
	. "leaf/core/error"
	"leaf/core/gate"
	"leaf/core/log"
	. "leaf/core/msg"
	. "leaf/core/tool"
	"leaf/model"
	"leaf/pb"
	"time"
)

const Login_Session_Time time.Duration = 10 * time.Minute

func getAccountSession(account interface{}) string {
	return MD5Str(fmt.Sprintf("%v%v", account, GetSpaceTime(Login_Session_Time)))
}

func ServerInfoHandler(agent gate.Agent, msg *PMsg) *Error {
	resp := msg.C2S().(*pb.S2C_ServerInfo)
	log.Release("ServerInfoHandler msg = %v", resp)

	var version, err = cache.GetInstance().Get(fmt.Sprintf(GLOBAL_GAMEINFO_VERSION, GetKeyPrefix())).Result()
	if RedisError(err) {
		return nil
	}

	resp.Version = proto.String(version)
	return nil
}

func GuestAuthHandler(agent gate.Agent, msg *PMsg) *Error {
	c2s := msg.C2S().(*pb.C2S_GuestAuth)
	s2c := msg.S2C().(*pb.S2C_GuestAuth)
	s2c.Account = proto.String("guest_" + c2s.GetAccount())
	return nil
}

func RegisterHandler(agent gate.Agent, msg *PMsg) *Error {
	c2s := msg.C2S().(*pb.C2S_Regs)
	log.Release("RegisterHandler start,msg:%v", c2s)

	if c2s.GetAccount() == "" {
		log.Release("RegisterHandler err:%v", Error_ArgIllegal)
		return Error_ArgIllegal
	}

	var dbAccount = model.FindDbAccount(c2s.GetAccount())
	if dbAccount != nil {
		if dbAccount.GetAccount() == c2s.GetAccount() {
			log.Release("RegisterHandler err:%v", Error_AccountExist)
			return Error_AccountExist
		}
	}
	dbAccount = &pb.DbAccount{}
	dbAccount.Account = c2s.Account
	dbAccount.Password = proto.String(MD5Str(c2s.GetPwd()))
	aid, err := model.InserOneDbAccount(dbAccount)
	if err != nil {
		log.Release("RegisterHandler err:%v", err)
		return ConvertError(err)
	}

	cache := cache.GetInstance()
	if cache == nil {
		log.Release("CreateUserNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	if !cache.Lock(RdKey(GLOBAL_LOCKERS_LOGIN, GetKeyPrefix()), c2s.GetAccount()) {
		return Error_DBErr
	}
	defer cache.UnLock(RdKey(GLOBAL_LOCKERS_LOGIN, GetKeyPrefix()), c2s.GetAccount())

	//创建session，后续通过session作为通行证
	sessionStr := getAccountSession(c2s.GetAccount())
	key := fmt.Sprintf(GAMER_REGISTER_SESSION, GetKeyPrefix(), getAccountSession(c2s.GetAccount()))
	if _, err := cache.Set(key, aid, 10*time.Minute).Result(); RedisError(err) {
		log.Release("RegisterHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	s2c := msg.S2C().(*pb.S2C_Regs)
	s2c.Session = proto.String(sessionStr)
	log.Release("RegisterHandler success,session:%v", s2c.GetSession())
	return nil
}

func LoginNewHandler(agent gate.Agent, msg *PMsg) *Error {
	c2s := msg.C2S().(*pb.C2S_Login)
	log.Release("LoginNewHandler start,c2s:%v", c2s)

	if c2s.GetAccount() == "" {
		log.Release("LoginNewHandler err:%v", Error_ArgIllegal)
		return Error_ArgIllegal
	}

	var dbAccount = model.FindDbAccount(c2s.GetAccount())
	if dbAccount == nil {
		log.Release("LoginNewHandler err:%v", Error_AccountNotExist)
		return Error_AccountNotExist
	}

	if dbAccount.GetAccount() != c2s.GetAccount() || dbAccount.GetPassword() != MD5Str(c2s.GetPwd()) {
		log.Release("LoginNewHandler err:%v", Error_PwdWrong)
		return Error_PwdWrong
	}

	var cache = cache.GetInstance()
	if cache == nil {
		log.Release("LoginNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	if !cache.Lock(RdKey(GLOBAL_LOCKERS_LOGIN, GetKeyPrefix()), dbAccount.GetId()) {
		log.Release("LoginNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}
	defer cache.UnLock(RdKey(GLOBAL_LOCKERS_LOGIN, GetKeyPrefix()), dbAccount.GetId())

	sessionStr := getAccountSession(c2s.GetAccount())
	s2c := msg.S2C().(*pb.S2C_Login)
	s2c.Session = proto.String(sessionStr)
	var dbUser = model.FindUserByAccountId(dbAccount.GetId())
	if dbUser == nil {
		key := fmt.Sprintf(GAMER_REGISTER_SESSION, GetKeyPrefix(), sessionStr)
		if _, err := cache.Set(key, fmt.Sprintf("%v", dbAccount.GetId()), Login_Session_Time).Result(); RedisError(err) {
			log.Release("LoginNewHandler err:%v", Error_DBErr)
			return Error_DBErr
		}
		return nil
	} else {
		s2c.Userid = dbUser.Userid
		status := &pb.LoginStatus{}
		status.Aid = proto.String(dbAccount.GetId())
		status.Session = proto.String(sessionStr)
		status.Status = proto.Int32(1)
		status.Role = dbUser
		key := fmt.Sprintf(GAMER_LOGIN_SESSION, GetKeyPrefix(), sessionStr)
		statusStr := DBStr(status)

		if _, err := cache.Set(key, statusStr, Login_Session_Time).Result(); RedisError(err) {
			log.Release("LoginNewHandler err:%v", Error_DBErr)
			return Error_DBErr
		}
	}

	log.Release("LoginNewHandler success,session:%v userid:%v", s2c.GetSession(), s2c.GetUserid())
	//加载玩家数据到redis缓存
	//cache.Set(fmt.Sprintf(GAMER_USER, GetKeyPrefix(), dbUser.GetUserid()), dbUser, true)
	return nil
}

// 创建角色
func CreateUserNewHandler(agent gate.Agent, msg *PMsg) *Error {
	c2s := msg.C2S().(*pb.C2S_CreateUser)
	log.Release("CreateUserNewHandler start,c2s", c2s)

	if c2s.GetSession() == "" || c2s.GetName() == "" {
		log.Release("CreateUserNewHandler err:%v", Error_ArgIllegal)
		return Error_ArgIllegal
	}

	cache := cache.GetInstance()
	if cache == nil {
		log.Release("CreateUserNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	aid, err := cache.Get(fmt.Sprintf(GAMER_REGISTER_SESSION, GetKeyPrefix(), c2s.GetSession())).Result()
	if RedisError(err) {
		log.Release("CreateUserNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	if !cache.Lock(RdKey(GLOBAL_LOCKERS_LOGIN, GetKeyPrefix()), aid) {
		log.Release("CreateUserNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}
	defer cache.UnLock(RdKey(GLOBAL_LOCKERS_LOGIN, GetKeyPrefix()), aid)

	if model.IsUserNameRepeated(c2s.GetName()) {
		log.Release("CreateUserNewHandler err:%v", Error_UserNameRepeated)
		return Error_UserNameRepeated
	}

	userId, errr := cache.ScriptInt64(RedsiScript_AddUserId, []string{fmt.Sprintf(GLOBAL_USERID, GetKeyPrefix())})
	if RedisError(errr) {
		log.Release("CreateUserNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	dbUser := &pb.DbUser{}
	dbUser.Accountid = proto.String(aid)
	dbUser.Sex = proto.Int32(c2s.GetSex())
	dbUser.Name = proto.String(c2s.GetName())
	dbUser.Userid = proto.Uint64(uint64(userId))
	if err := cache.Set(fmt.Sprintf(GAMER_USER, GetKeyPrefix(), dbUser.GetUserid()), DBStr(dbUser), 0).Err(); RedisError(err) {
		log.Release("CreateUserNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	sessionStr := getAccountSession(aid)
	status := &pb.LoginStatus{}
	status.Aid = proto.String(aid)
	status.Session = proto.String(sessionStr)
	status.Status = proto.Int32(1)
	status.Role = dbUser
	key := fmt.Sprintf(GAMER_LOGIN_SESSION, GetKeyPrefix(), sessionStr)
	if _, err := cache.Set(key, DBStr(status), Login_Session_Time).Result(); err != nil {
		return Error_DBErr
	}
	s2c := msg.S2C().(*pb.S2C_CreateUser)
	s2c.Session = proto.String(sessionStr)
	s2c.Userid = proto.Uint64(dbUser.GetUserid())
	log.Release("CreateUserNewHandler success,session:%v userid:%v", s2c.GetSession(), s2c.GetUserid())
	return nil
}

func LoginUseRoleHandler(agent gate.Agent, msg *PMsg) *Error {
	c2s := msg.C2S().(*pb.C2S_LoginUseRole)
	log.Release("LoginUseRoleHandler start,c2s:%v", c2s)

	cache := cache.GetInstance()
	if cache == nil {
		log.Release("CreateUserNewHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	data, err := cache.Get(fmt.Sprintf(GAMER_LOGIN_SESSION, GetKeyPrefix(), c2s.GetSession())).Result()
	if RedisError(err) {
		log.Release("LoginUseRoleHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	status := &pb.LoginStatus{}
	if !ParseDBStr(data, status) {
		log.Release("LoginUseRoleHandler err:%v", Error_DBErr)
		return Error_DBErr
	}

	aid := status.GetAid()
	if !cache.Lock(RdKey(GLOBAL_LOCKERS_LOGIN, GetKeyPrefix()), aid) {
		log.Release("LoginUseRoleHandler err:%v", Error_DBErr)
		return Error_DBErr
	}
	defer cache.UnLock(RdKey(GLOBAL_LOCKERS_LOGIN, GetKeyPrefix()), aid)

	logicNode := cluster.GetBestNode(2)
	if logicNode == nil {
		log.Release("LoginUseRoleHandler err:%v", Error_NoneLogicNode)
		return Error_NoneLogicNode
	}

	var gateAddr = &pb.S2C_GateAddr{}
	if err := logicNode.Call("GetLogicAddr", nil, gateAddr); IsError(err) {
		log.Release("LoginUseRoleHandler err:%v", err)
		return ConvertError(err)
	} else {
		status.Status = proto.Int32(2)
		key := fmt.Sprintf(GAMER_LOGIN_SESSION, GetKeyPrefix(), status.GetSession())
		if _, err := cache.Set(key, DBStr(status), Login_Session_Time).Result(); err != nil {
			return Error_DBErr
		}

		s2c := msg.S2C().(*pb.S2C_LoginUseRole)
		s2c.Addr = gateAddr.Addr
		s2c.Userid = status.GetRole().Userid
		log.Release("LoginUseRoleHandler success,addr:%v userId:%v", s2c.GetAddr(), s2c.GetUserid())
		return nil
	}
}

func LoginUseRoleTestHandler(agent gate.Agent, msg *PMsg) *Error {
	log.Release("LoginUseRoleTestHandler...")

	logicNode := cluster.GetBestNode(2)
	if logicNode == nil {
		log.Release("LoginUseRoleHandler err:%v", Error_NoneLogicNode)
		return Error_NoneLogicNode
	}

	var gateAddr = &pb.S2C_GateAddr{}
	err := logicNode.Call("GetLogicAddr", nil, gateAddr)
	if IsError(err) {
		log.Release("LoginUseRoleHandler err:%v", err)
		return ConvertError(err)
	}

	s2c := msg.S2C().(*pb.S2C_LoginUseRole)
	s2c.Addr = gateAddr.Addr
	s2c.Userid = proto.Uint64(13)
	log.Release("LoginUseRoleTestHandler success")
	return nil
}
